#include "stdafx.h"

#include "Shader.h"
#include "Renderer.h"
#include "ShaderHelper.h"

#include<atlpath.h>

using namespace Rendering;
using namespace DirectX;

/// <summary>Constructor.</summary>
/// <param name="renderer">The renderer to render this object.</param>
/// <param name="vertexShaderFile">Name of the vertex shader file.</param>
/// <param name="pixelShaderFile">Name of the pixel shader file.</param>
/// <param name="elementLayout">The layout of the element.</param>
/// <param name="layoutDescNumElems">Number of descriptions for the element.</param>
Shader::Shader(Renderer* renderer, string vertexShaderFile, string pixelShaderFile, D3D11_INPUT_ELEMENT_DESC elementLayout[], int layoutDescNumElems)
{
	ID3D11DevicePtr device = renderer->Device();
	ShaderHelper::LoadVertexShader(device, vertexShaderFile, elementLayout, layoutDescNumElems, &m_vertexShader, &m_inputLayout);
	ShaderHelper::LoadPixelShader(device, pixelShaderFile, &m_pixelShader);

	AppendSamplerState(device);
}

/// <summary>Renders the object.</summary>
/// <param name="renderer">The renderer to render this object.</param>
void Shader::Render(_In_ Renderer* renderer)
{
	ID3D11DeviceContext1Ptr context = renderer->Context();
	
	context->VSSetShader(m_vertexShader, nullptr, 0);
    context->PSSetShader(m_pixelShader, nullptr, 0);

	context->IASetInputLayout(m_inputLayout);
	std::vector<ID3D11SamplerState*> samplerStatePointers;
	if (!m_samplerStates.empty())
	{
		for(ID3D11SamplerStatePtr samplerState : m_samplerStates)
		{
			samplerStatePointers.push_back(samplerState);
		}
		context->PSSetSamplers(0, static_cast<UINT>(m_samplerStates.size()), samplerStatePointers.data());
	}
}

/// <summary>Creates and appends a new sampler state to the m_samplerStates.</summary>
/// <param name="device">The direct3d device to create a sampler state.</param>
void Shader::AppendSamplerState(_In_ ID3D11Device* device)
{
	ID3D11SamplerStatePtr samplerState;
	CreateSamplerState(device, &samplerState);
	m_samplerStates.push_back(samplerState.Detach());
}

/// <summary>Creates a new sampler state from color map description.</summary>
/// <param name="device">The direct3d device to create a sampler state.</param>
/// <param name="colorMapDesc">The color map description.</param>
/// <param name="samplerState">The out pointer to hold the sampler state.</param>
HRESULT Shader::CreateSamplerState(_In_ ID3D11Device* device, _In_ D3D11_SAMPLER_DESC colorMapDesc, _Out_ ID3D11SamplerState** samplerState)
{
	return device->CreateSamplerState(&colorMapDesc, samplerState);
}

/// <summary>Creates a new sampler state.</summary>
/// <param name="device">The direct3d device to create a sampler state.</param>
/// <param name="samplerState">The out pointer to hold the sampler state.</param>
void Shader::CreateSamplerState(_In_ ID3D11Device* device, _Out_ ID3D11SamplerState** samplerState )
{
	*samplerState = nullptr;

	D3D11_SAMPLER_DESC sampDesc;
    ZeroMemory(&sampDesc, sizeof(sampDesc));

// State					Default Value
//-----------------------------------------------------
//	Filter				MIN_MAG_MIP_LINEAR 
//	AddressU			Clamp 
//	AddressV			Clamp 
//	AddressW			Clamp 
//	MinLOD -			3.402823466e+38F (-FLT_MAX) 
//	MaxLOD				3.402823466e+38F (FLT_MAX) 
//	MipMapLODBias		0.0f 
//	MaxAnisotropy		16 
//	ComparisonFunc		Never 
//	BorderColor			float4(0.0f,0.0f,0.0f,0.0f) 
//	Texture				N/A 

    sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
    sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
    sampDesc.MinLOD = 0;
    sampDesc.MaxLOD = FLT_MAX;
	ID3D11SamplerStatePtr internalSamplerState;
    IF_FAILED_THROW_HR(device->CreateSamplerState(&sampDesc, &internalSamplerState));

	*samplerState = internalSamplerState.Detach();
}